package yl.hs.bmipfull.service.report.impl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import yl.hs.bmipfull.daos.host.IProductionLineRawConfigDao;
import yl.hs.bmipfull.daos.material.IRawMaterialInfoDao;
import yl.hs.bmipfull.daos.material.IRawMaterialPriceDao;
import yl.hs.bmipfull.daos.production.IProductShipOrderDao;
import yl.hs.bmipfull.daos.production.IProductionRecordDao;
import yl.hs.bmipfull.daos.production.IProductionRecordDetailsDao;
import yl.hs.bmipfull.daos.salemanage.ISaleContractDao;
import yl.hs.bmipfull.pojo.host.ProductionLineRawConfigEntity;
import yl.hs.bmipfull.pojo.laboratory.ProductOverageEntity;
import yl.hs.bmipfull.pojo.material.RawMaterialInfoEntity;
import yl.hs.bmipfull.pojo.material.RawMaterialPriceEntity;
import yl.hs.bmipfull.pojo.production.ProductShipOrderEntity;
import yl.hs.bmipfull.pojo.production.ProductionRecordDetailsEntity;
import yl.hs.bmipfull.pojo.production.ProductionRecordEntity;
import yl.hs.bmipfull.pojo.system.DictItemEntity;
import yl.hs.bmipfull.service.laboratory.IProductOverageService;
import yl.hs.bmipfull.service.material.IRawMaterialInfoService;
import yl.hs.bmipfull.service.production.IProductShipOrderService;
import yl.hs.bmipfull.service.production.IProductionRecordService;
import yl.hs.bmipfull.service.report.IProductionStatisticsService;
import yl.hs.bmipfull.service.system.IDataDictService;
import yl.hs.bmipfull.utils.*;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.production.ProductionRecordDetailsVO;
import yl.hs.bmipfull.viewmodels.report.ProductionRecordCostDetailsVO;
import yl.hs.bmipfull.viewmodels.report.ProductionRecordCostVO;
import yl.hs.bmipfull.viewmodels.report.ProductionSalesComparisonVO;
import yl.hs.bmipfull.viewmodels.statistics.DailyProductionCostStatistics;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 作用:   <br/>
 * 创建时间: 2022-02-23 14:42 <br/>
 * 生产统计service实现
 *
 * @author 吴高丰
 */
@Slf4j
@Service
public class ProductionStatisticsServiceImpl implements IProductionStatisticsService {


    @Override
    public List<Object> vehicleDeliveryStatistics(PageQuery pageQuery, String productCateSn) {
        try {
            List<Object> result = new ArrayList<>();
            val productShipOrderEntities = shipOrderService.queryList(pageQuery, productCateSn);
            val collect = productShipOrderEntities.stream().collect(Collectors.groupingBy(ProductShipOrderEntity::getTruckCode));
            var dictList = dataDictService.findDictItemByCode("productBuildWay");
            collect.keySet().forEach(t -> {
                val value = collect.get(t);
                List<String> list = new ArrayList<>();
                List<Object> objects = new ArrayList<>();
                BigDecimal number = BigDecimal.valueOf(0);
                for (ProductShipOrderEntity productShipOrderEntity : value) {
                    number = number.add(productShipOrderEntity.getQuantity());
                    if (productShipOrderEntity.getProductTags() == null) {
                        objects.add("ss");
                    } else if (!productShipOrderEntity.getProductTags().contains("productBuildWay")) {
                        objects.add("ss");
                    } else {
                        list.add(productShipOrderEntity.getProductTags());
                    }
                }
                Map<String, Object> map = new HashMap<>();
                for (DictItemEntity item : dictList) {
                    map.put(item.getDataValue(), list.stream().filter(d -> d.contains(item.getDataValue())).toList().size());
                }
                map.put("quantity", number);
                map.put("car", t);
                map.put("other", objects.size());
                result.add(map);
            });
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public Map<String,Object> queryProductLineConsumption(PageQuery pageQuery, String productCateSn) throws Exception {
        Map<String,Object> resultMap=new HashMap<>();
        List<Object> result = new ArrayList<>();
        List<ProductionRecordEntity> productionRecordEntities = productionRecordService.queryList(pageQuery, productCateSn);

       var idList = productionRecordEntities.stream().map(ProductionRecordEntity::getId).toList();
       var scfl=productionRecordEntities.stream().collect(Collectors.summarizingDouble(ProductionRecordEntity::getActualOutput)).getSum();
        if (idList != null && idList.size() > 0) {
            List<ProductionRecordDetailsVO> detailsVOList = recordDetailsDao.queryListByRecordIdList(idList);
            for (var recordDetail : detailsVOList) {
                RawMaterialInfoEntity rawMaterialInfo = rawInfoService.findBySn(recordDetail.getRawMaterialSn());
                Map<String, Object> map = new HashMap<>();
                if(rawMaterialInfo!=null){
                    map.put("rmCateName", rawMaterialInfo.getRmCateName());
                    map.put("rmName", rawMaterialInfo.getRmName());
                    map.put("rmSpec", rawMaterialInfo.getRmSpec());
                }
                map.put("consumptionQuantity", recordDetail.getConsumptionQuantity().divide(BigDecimal.valueOf(1000),RoundingMode.CEILING));
                map.put("differenceQuantity", Math.abs(Double.parseDouble(recordDetail.getDifferenceQuantity().toString())/1000));
                map.put("configRatioQuantity", recordDetail.getConfigRatioQuantity().divide(BigDecimal.valueOf(1000),RoundingMode.CEILING));
                if (recordDetail.getConfigRatioQuantity() != null || recordDetail.getDifferenceQuantity() != null) {
                    map.put("errorRate", 0);
                } else {
                    map.put("errorRate", recordDetail.getConfigRatioQuantity().divide(BigDecimal.valueOf(1000),RoundingMode.CEILING).divide(recordDetail.getDifferenceQuantity().divide(BigDecimal.valueOf(1000),RoundingMode.CEILING), 3, RoundingMode.HALF_UP));
                }

                result.add(map);
            }
        }
        resultMap.put("list",result);
        resultMap.put("scfl",scfl);
        return resultMap;
    }

    @Override
    public List<Map<String,Object>> queryProductConsumption(PageQuery pageQuery, String productCateSn) throws Exception {
        List<Map<String,Object>> result = new ArrayList<>();
        List<ProductionRecordEntity> productionRecordEntities = productionRecordService.queryList(pageQuery, productCateSn);
        var productNameList=recordDao.queryListGroupByProductName(pageQuery.getQuery());
        for (var product: productNameList) {
            var idList = productionRecordEntities.stream().filter(t->t.getProductName().equals(product)).map(ProductionRecordEntity::getId).toList();
            if (idList != null && idList.size() > 0) {
                Map<String,Object> map= new HashMap<>();
                List<Object> RecordDetailList=new ArrayList<>();
                List<ProductionRecordDetailsVO> detailsVOList = recordDetailsDao.queryListByRecordIdList(idList);
                var scfl=productionRecordEntities.stream().filter(t->t.getProductName().equals(product)).collect(Collectors.summarizingDouble(ProductionRecordEntity::getActualOutput)).getSum()/1000;
                for (var recordDetail : detailsVOList) {
                    RawMaterialInfoEntity rawMaterialInfo = rawInfoService.findBySn(recordDetail.getRawMaterialSn());
                    Map<String, Object> RecordDetailMap = new HashMap<>();
                    if(rawMaterialInfo!=null){
                        RecordDetailMap.put("rmCateName", rawMaterialInfo.getRmCateName());
                        RecordDetailMap.put("rmName", rawMaterialInfo.getRmName());
                        RecordDetailMap.put("rmSpec", rawMaterialInfo.getRmSpec());
                    }
                    RecordDetailMap.put("consumptionQuantity", recordDetail.getConsumptionQuantity().divide(BigDecimal.valueOf(1000),RoundingMode.CEILING));
                    RecordDetailMap.put("differenceQuantity", Math.abs(Double.parseDouble(recordDetail.getDifferenceQuantity().toString())/1000));
                    RecordDetailMap.put("configRatioQuantity", recordDetail.getConfigRatioQuantity().divide(BigDecimal.valueOf(1000),RoundingMode.CEILING));
                    // 为0为null处理
                    if (recordDetail.getConfigRatioQuantity() == null ||
                            recordDetail.getDifferenceQuantity() == null ||
                            recordDetail.getDifferenceQuantity().compareTo(BigDecimal.ZERO) == 0 ||
                            recordDetail.getConfigRatioQuantity().compareTo(BigDecimal.ZERO) == 0) {
                        RecordDetailMap.put("errorRate", 0);
                    } else {
                        RecordDetailMap.put("errorRate",
                                recordDetail.getDifferenceQuantity().divide
                                                (BigDecimal.valueOf(1000), RoundingMode.CEILING).
                                        divide(recordDetail.getConfigRatioQuantity().divide(BigDecimal.valueOf(1000), RoundingMode.CEILING), 3, RoundingMode.HALF_UP));
                    }
                    RecordDetailList.add(RecordDetailMap);
                }
                map.put("productName",product);
                map.put("scfl",scfl);
                map.put("reportList",RecordDetailList);
                result.add(map);
            }
        }
        return result;
    }

    @Override
    public List<Object> querySaleAndProductionGroupDay(String startTime, String endTime,String productLineSN) throws ParseException {
        List<Object> result = new ArrayList<>();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        long day = (df.parse(endTime).getTime() - df.parse(startTime).getTime()) / (1000 * 24 * 60 * 60);
        for (long i = 0; i <= day; i++) {
            Map<String, Object> map = new HashMap<>();

            String summaryTime = df.format(new Date(df.parse(startTime).getTime() + (i) * 24 * 60 * 60 * 1000));
            if(i==0){
                summaryTime = df2.format(new Date(df2.parse(startTime).getTime()));
            }
            String newEndTime = df.format(new Date(df.parse(startTime).getTime() + (i + 1) * 24 * 60 * 60 * 1000));
            if(i==day){
                newEndTime = df2.format(new Date(df2.parse(endTime).getTime()));
            }
            List<String> lineSNList=new ArrayList<>();
            if (productLineSN !=null && productLineSN.split(",").length>0){
                lineSNList= List.of(productLineSN.split(","));
            }
            double betonSaleNetWeight = shipOrderDao.querySaleGroupDay(HsApp.getSystemSet(CK.BetonSysCode), summaryTime, newEndTime,lineSNList);
            double mortarSaleNetWeight = shipOrderDao.querySaleGroupDay(HsApp.getSystemSet(CK.MortarSnSysCode), summaryTime, newEndTime,lineSNList);
            double betonProductionNetWeight = recordDao.queryProductionGroupDay("商砼", summaryTime, newEndTime,lineSNList);
            double mortarProductionNetWeight = recordDao.queryProductionGroupDay("砂浆", summaryTime, newEndTime,lineSNList)/1000;
            if (betonSaleNetWeight != 0 || mortarSaleNetWeight != 0 || betonProductionNetWeight != 0 || mortarProductionNetWeight != 0) {
                map.put("summaryTime", summaryTime);
                map.put("betonSaleNetWeight", betonSaleNetWeight);
                map.put("mortarSaleNetWeight", mortarSaleNetWeight);
                map.put("betonProductionNetWeight", betonProductionNetWeight);
                map.put("mortarProductionNetWeight", mortarProductionNetWeight);
                map.put("betonDifferenceNetWeight", Math.abs(betonSaleNetWeight - betonProductionNetWeight));
                map.put("mortarDifferenceNetWeight", Math.abs(mortarSaleNetWeight - mortarProductionNetWeight));
                result.add(map);
            }

        }

        return result;
    }

    @Override
    public List<ProductionRecordCostVO> queryProductionRecordCost(PageQuery pageQuery, String productCateSn) {

        List<ProductionRecordCostVO> recordCostVOList = new ArrayList<>();
        try {
            //查询主机配置的原材信息
            List<String> configRmSnSet = rawConfigDao.queryByProductCateSn(productCateSn).stream().map(ProductionLineRawConfigEntity::getRawSn)
                    .collect(Collectors.toList());
            List<RawMaterialInfoEntity> rmInfoList = rmDao.queryListBySnList(configRmSnSet);
            List<RawMaterialPriceEntity> allRmPriceList = rawMaterialPriceDao.queryByRmSnList(configRmSnSet);
            List<ProductionRecordEntity> recordList = productionRecordService.queryList(pageQuery, productCateSn);
            List<ProductionRecordDetailsEntity> allPRList = productionRecordService.queryDetailsList(pageQuery, productCateSn);
            recordList.forEach(record -> {
                List<ProductionRecordCostVO> tempRecordCostVOList = recordCostVOList.stream().filter(t -> {
                            boolean sameDay = DateUtils.isSameDay(t.getStartTime(), record.getStartTime());
                            return sameDay && t.getProjectName().equals(record.getProjectName()) && t.getProjectPart().equals(record.getProjectPart())
                                    && t.getProductName().equals(record.getProductName()) && t.getProductCate().equals(record.getProductCate());
                }).toList();
                ProductionRecordCostVO recordCostVO;
                if (tempRecordCostVOList != null && tempRecordCostVOList.size() > 0) {
                    recordCostVO = tempRecordCostVOList.get(0);
                }
                else {
                    recordCostVO = new ProductionRecordCostVO();
                    recordCostVO.setProjectName(record.getProjectName());
                    recordCostVO.setProjectPart(record.getProjectPart());
                    recordCostVO.setProductName(record.getProductName());
                    recordCostVO.setProductCate(record.getProductCate());
                    recordCostVO.setStartTime(record.getStartTime());
                    recordCostVO.setSumNetWeight(0.00);
                    recordCostVO.setTruckCount(0);
                    recordCostVOList.add(recordCostVO);
                }
                var taskFL = recordList.stream().filter(t -> t.getProjectName().equals(record.getProjectName()) && t.getProjectPart().equals(record.getProjectPart())
                        && t.getProductName().equals(record.getProductName())).collect(Collectors.summarizingDouble(ProductionRecordEntity::getActualOutput)).getSum();
                var truckCount = recordList.stream().filter(t -> t.getProjectName().equals(record.getProjectName()) && t.getProjectPart().equals(record.getProjectPart())
                        && t.getProductName().equals(record.getProductName()) && !Tl.isEmpty(t.getCarGroup()) && t.getCarGroup().equals("1.0")).count();
                recordCostVO.setSumNetWeight(taskFL);
                recordCostVO.setTruckCount((int) truckCount);
                if (recordCostVO.getDetailsVOList() == null) {
                    recordCostVO.setDetailsVOList(new ArrayList<>());
                }
                List<ProductionRecordCostDetailsVO> detailsVOList = recordCostVO.getDetailsVOList();
                assert record.getId() != null;
                var rID = record.getId().toString();
                var recordDetailList = allPRList.stream().filter(t->t.getProductionRecordId().toString().equals(rID)).toList();
                Calendar cal = Calendar.getInstance();
                cal.setTime(record.getStartTime());
                int year = cal.get(Calendar.YEAR);
                int month = cal.get(Calendar.MONTH);
                recordDetailList.forEach(recordDetail -> {
                    var tempRawInfo = rmInfoList.stream().filter(t -> t.getSn().equals(recordDetail.getRawMaterialSn())).findFirst();
                    if (tempRawInfo.isPresent()) {
                        RawMaterialInfoEntity rawInfo = tempRawInfo.get();
                        RawMaterialPriceEntity priceEntity =null;
                        if(allRmPriceList.size()>0){
                            var rmPriceOpt = allRmPriceList.stream().filter(t->t.getRmSn().equals(rawInfo.getSn()) && t.getPriceYear()==year && t.getPriceMonth()==month).findFirst();
                            if(rmPriceOpt.isPresent()){
                                priceEntity = rmPriceOpt.get();
                            }
                        }
                        var tempDetailVO =
                                detailsVOList.stream().filter(t -> t.getRmName().equals(rawInfo.getRmName()) &&
                                        t.getRmSpec().equals(rawInfo.getRmSpec())).findFirst();
                        ProductionRecordCostDetailsVO recordCostDetailsVO;
                        if (tempDetailVO.isPresent()) {
                            recordCostDetailsVO = tempDetailVO.get();
                            recordCostDetailsVO.setQuantity(recordCostDetailsVO.getQuantity()
                                    .add(recordDetail.getConsumptionQuantity().divide(BigDecimal.valueOf(1000))));
                            recordCostDetailsVO.setAmount(recordCostDetailsVO.getAmount()
                                    .add(recordCostDetailsVO.getQuantity().multiply(recordCostDetailsVO.getPrice())));
                        } else {
                            recordCostDetailsVO = new ProductionRecordCostDetailsVO();
                            recordCostDetailsVO.setRmName(rawInfo.getRmName());
                            recordCostDetailsVO.setPrice(priceEntity == null ? BigDecimal.ZERO : priceEntity.getPrice());
                            recordCostDetailsVO.setRmSpec(rawInfo.getRmSpec());
                            recordCostDetailsVO.setQuantity(recordDetail.getConsumptionQuantity().divide(BigDecimal.valueOf(1000)));
                            recordCostDetailsVO.setAmount(recordCostDetailsVO.getQuantity().multiply(recordCostDetailsVO.getPrice()));
                            detailsVOList.add(recordCostDetailsVO);
                        }
                        recordCostVO.setTotalDetail(recordCostVO.getTotalDetail()+recordCostDetailsVO.getQuantity().doubleValue());
                    }
                });
            });

        } catch (Exception e) {
            e.printStackTrace();
            Log.error(e);
            Log.error("统计消耗统计错误");
        }
       
        return recordCostVOList;
    }

    @Override
    public List<ProductionRecordEntity> mortarProductionRecord(String startTime, String endTime) {
        return recordDao.mortarProductionRecord(startTime,endTime);
    }

    @Override
    public List<Map<String, Object>> queryProjectProductionCost(PageQuery pageQuery, String productCateSn) {
        try {
            List<String> configRmSnSet = rawConfigDao.queryByProductCateSn(productCateSn).stream().map(ProductionLineRawConfigEntity::getRawSn)
                    .collect(Collectors.toList());
            List<RawMaterialInfoEntity> rmInfoList = rmDao.queryListBySnList(configRmSnSet);
            //List<RawMaterialPriceEntity> allRmPriceList = rawMaterialPriceDao.queryByRmSnList(configRmSnSet);
            List<ProductionRecordEntity> recordList = productionRecordService.queryList(pageQuery, productCateSn);
            List<ProductionRecordDetailsEntity> allPRList = productionRecordService.queryDetailsList(pageQuery, productCateSn);

            var group = recordList.stream().collect(Collectors.groupingBy(r -> r.getProjectName() + "|" + r.getProductCate() + "|" + r.getProductName()));
            List<Map<String, Object>> data = new ArrayList<>();

            for (var key : group.keySet()) {
                Map<String, Object> dItem = new HashMap<>();
                var keyArray = key.split("\\|");
                var kd = group.get(key);
                dItem.put("projectName", keyArray[0]);
                dItem.put("productCate", keyArray[1]);
                dItem.put("productName", keyArray[2]);
                dItem.put("sumNetWeight", kd.stream().collect(Collectors.summarizingDouble(ProductionRecordEntity::getActualOutput)).getSum()/1000);
                var minTime = kd.stream().min(Comparator.comparing(ProductionRecordEntity::getStartTime));
                var maxTime = kd.stream().max(Comparator.comparing(ProductionRecordEntity::getStartTime));
                var title = "";
                var stf = new SimpleDateFormat("yyyy-MM-dd");
                if (minTime.isPresent()) {
                    title = stf.format(minTime.get().getStartTime());
                    if (maxTime.isPresent()) {
                        title += " - " + stf.format(maxTime.get().getStartTime());
                    }
                }

                dItem.put("title", title);
                dItem.put("truckCount", kd.stream().filter(t -> "1".equals(t.getCarGroup())).count());
                var kdSNs = kd.stream().map(ProductionRecordEntity::getId).collect(Collectors.toList());
                var details = allPRList.stream().filter(t -> kdSNs.contains(t.getProductionRecordId())).collect(Collectors.toList());
                var rmGroup = details.stream().collect(Collectors.groupingBy(ProductionRecordDetailsEntity::getRawMaterialSn));
                List<ProductionRecordCostDetailsVO> detailsVOList = new ArrayList<>();
                rmGroup.forEach((k, v) -> {
                    var rm = rmInfoList.stream().filter(r -> r.getSn().equals(k)).findFirst();
                    if (rm.isPresent()) {
                        var ro = rm.get();

                        var ri = new ProductionRecordCostDetailsVO();
                        ri.setRmName(ro.getRmName());
                        ri.setRmSpec(ro.getRmSpec());
                        ri.setAmount(BigDecimal.ZERO);
                        ri.setPrice(BigDecimal.ZERO);
                        ri.setQuantity(v.stream().filter(Objects::nonNull).map(ProductionRecordDetailsEntity::getConsumptionQuantity).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.valueOf(1000),RoundingMode.CEILING));
                        detailsVOList.add(ri);
                    }
                });
                dItem.put("detailsVOList", detailsVOList);
                data.add(dItem);
            }
            return data;
        }
        catch (Exception ee){
            log.error("获取工程消耗成本错误",ee);
            return new ArrayList<>();
        }
    }

    @Override
    public List<ProductionSalesComparisonVO> queryProductionSalesComparison(PageQuery pageQuery, String productCateSn) throws Exception {

        List<ProductionSalesComparisonVO> comparisonList = new ArrayList<>();
        List<ProductionRecordEntity> productionRecordList = recordService.queryList(pageQuery, productCateSn);
        var productShipOrderList = shipOrderService.queryList(pageQuery, productCateSn);
        List<ProductOverageEntity> overList = productOverageService.queryList(pageQuery);
        Set<String> productName = productionRecordList.stream().map(ProductionRecordEntity::getProductName).collect(Collectors.toSet());
        productName.addAll(productShipOrderList.stream().map(ProductShipOrderEntity::getProductName).collect(Collectors.toSet()));
        productName.forEach(t -> {
            if (t != null && !"".equals(t)) {
                ProductionSalesComparisonVO comparisonVO = new ProductionSalesComparisonVO();
                double recordOutput = productionRecordList.stream()
                        .filter(f -> f.getProductName().equals(t)).collect(Collectors.summarizingDouble(ProductionRecordEntity::getActualOutput)).getSum()/1000;
                comparisonVO.setProductionQuantity(BigDecimal.valueOf((double) Math.round(recordOutput * 100) / 100));
                double shiOrderOutput = productShipOrderList.stream()
                        .filter(f -> f.getProductName().equals(t)).collect(Collectors.summarizingDouble(
                                sum -> Double.parseDouble(sum.getQuantity().toString())
                        )).getSum();
                comparisonVO.setSalesQuantity(BigDecimal.valueOf((double) Math.round(shiOrderOutput * 100) / 100));
                comparisonVO.setProductName(t);
                var overOutput = overList.stream()
                        .filter(f -> f.getProductName().equals(t)).collect(Collectors.summarizingDouble(
                                sum -> Double.parseDouble(sum.getOverageWeight().toString())
                        )).getSum();
                comparisonVO.setSurplusQuantity(BigDecimal.valueOf((double) Math.round(overOutput * 100) / 100));
                comparisonList.add(comparisonVO);
            }
        });
        return comparisonList;
    }

    @Override
    public List<Map<String, Object>> queryProjectShipSummary(String cateSN, Date startTime, Date endTime) {
        var orders = shipOrderDao.queryTimeRangeCateOrders(cateSN,startTime,endTime);
        var pGroup = orders.stream().collect(Collectors.groupingBy(ProductShipOrderEntity::getProjectSN,
                Collectors.groupingBy(ProductShipOrderEntity::getProjectName)));
        var list = new ArrayList<Map<String,Object>>();
        for (var sn:pGroup.keySet()){
            var snGroup = pGroup.get(sn);
            for (var name:snGroup.keySet()){
                Map<String,Object> item = new HashMap<>();
                item.put("sn",sn);
                item.put("projectName",name);
                item.put("cateSN",cateSN);
                item.put("startTime",startTime);
                item.put("endTime",endTime);
                var sale = saleContractDao.findByProjectSN(sn);
                item.put("customer",sale==null?"济源常春藤建材科技有限公司":sale.getCustomerName());
                var orderList = snGroup.get(name);
                var quantity = orderList.stream().map(t->{
                    if(t.getState()< 10){
                        return t.getQuantity();
                    }
                    else{
                        return t.getShipmentReviewQuantity();
                    }
                }).reduce(BigDecimal.ZERO,BigDecimal::add);
               var amount =  orderList.stream().map(t->{
                    if(t.getState()< 10){
                        return t.getQuantity().multiply(t.getPrice());
                    }
                    else{
                        return t.getShipmentReviewQuantity().multiply(t.getShipmentReviewPrice());
                    }
                }).reduce(BigDecimal.ZERO,BigDecimal::add);
                item.put("quantity",quantity);
                item.put("amount",amount);
                list.add(item);
            }
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> queryProjectDaySummary(String cateSN, String projectSN, Date startTime, Date endTime) {
        var orders = shipOrderDao.queryTimeRangeProjectCateOrders(cateSN,projectSN, startTime,endTime);
        var pGroup = orders.stream().collect(Collectors.groupingBy(t->Tl.getDateString(t.getOutTime(),"yyyy-MM-dd"), Collectors.groupingBy(ProductShipOrderEntity::getProductSN,
                Collectors.groupingBy(ProductShipOrderEntity::getProductName,Collectors.groupingBy(ProductShipOrderEntity::getProductTags)))));
        var list = new ArrayList<Map<String,Object>>();
        for (var date: pGroup.keySet()) {
            var dateGroup = pGroup.get(date);
            for (var sn : dateGroup.keySet()) {
                var snGroup = dateGroup.get(sn);
                for (var name : snGroup.keySet()) {
                    var nameGroup = snGroup.get(name);
                    for(var tag : nameGroup.keySet()) {
                        Map<String, Object> item = new HashMap<>();
                        item.put("sn", sn);
                        item.put("date", date);
                        item.put("productName", name);
                        var orderList = nameGroup.get(tag);
                        var quantity = orderList.stream().map(t -> {
                            if (t.getState() < 10) {
                                return t.getQuantity();
                            } else {
                                return t.getShipmentReviewQuantity();
                            }
                        }).reduce(BigDecimal.ZERO, BigDecimal::add);
                        var price = orderList.stream().map(t -> {
                            if (t.getState() < 10) {
                                return shipOrderDao.getProductPrice(t.getContractSN(),t.getProductSN(),t.getOutTime(),t.getProductTags());
                            } else {
                                return t.getShipmentReviewPrice();
                            }
                        }).reduce(BigDecimal.ZERO, BigDecimal::add).divide(new BigDecimal(orderList.size()), RoundingMode.CEILING);
                        var buildWayList = readPumpWay(tag);
                        item.put("productBuildWay", String.join(",", buildWayList));
                        item.put("quantity", quantity);
                        item.put("price", price);
                        item.put("amount", quantity.multiply(price));
                        list.add(item);
                    }
                }
            }
        }
        return list.stream().sorted(Comparator.comparing(m -> m.get("date").toString())).toList();
    }
    private String readPumpWay(String tag){
        var value = new ArrayList<String>();
        var st = tag.split(";");
        for (var t : st){
            value.add(t.split(":")[1].replace(",",""));
        }
        return String.join(",",value);
    }


    private String[] companyNames = {"常春藤", "国泰"};
    private String[] prefix_titles = {"日期", "公司名称", "产量（方）"};
    private String[] suffix_titles = {"总成本(元)", "成本(元/方)"};

    @Override
    public Map<String, Object> getProductionBoardData(Integer year, Integer month) {

        Map<String, Object> resultMap = Maps.newLinkedHashMap();

        List<String> titles = Lists.newArrayList();
        titles.addAll(Arrays.asList(prefix_titles));
        // 填入消耗原材种类
        List<String> materialsByMonth = recordDetailsDao.findMaterialsByMonth(year, month);
        titles.addAll(materialsByMonth);
        titles.addAll(Arrays.asList(suffix_titles));

        List<List<Map<String, Object>>> costDataDetails = Lists.newArrayList();

        List<DailyProductionCostStatistics> productionBoardData = recordDetailsDao.getProductionBoardData(year, month);
        List<Map<String, Object>> costData = recordDetailsDao.monthQuantityAmount(year, month);


        // 填充原材消耗数据及产量、成本
        for (int i = 1; i <= DateUtil.daysOfMonth(year, month); i++) {

            String days = i + "";

            List<Map<String, Object>> dayData = Lists.newArrayList();

            for (String companyName : companyNames) {
                // 原材成本
                BigDecimal materialCost = BigDecimal.ZERO;

                // 表单内容对象
                Map<String, Object> innerMap = Maps.newLinkedHashMap();

                innerMap.put("公司名称", companyName);

                // 产量
                String actualOutput = "0";
                // 筛选公司下的某天的实际产量
                for (Map<String, Object> map : costData.stream().filter(item ->
                        String.valueOf(item.get("unit")).equals(companyName) && String.valueOf(item.get("days")).equals(days)
                ).toList()) {
                    actualOutput = map.get("actualOutput") + "";
                }

                innerMap.put("产量（方）", actualOutput);

                // 原材消耗详情
                for (String materialName : materialsByMonth) {
                    String rawMaterialSn = "";
                    String materialCostWeight = "0";
                    for (DailyProductionCostStatistics target : productionBoardData.stream().filter(
                            item ->
                                    (item.getRmName().equals(materialName)
                                            && (item.getDays()).equals(days)
                                            && item.getUnit().equals(companyName)
                                    )).toList()) {
                        materialCostWeight = target.getConsumptionQuantity();
                        rawMaterialSn = target.getRawMaterialSn();
                    }

                    // 原材价格
                    BigDecimal price = rmDao.getRMCostPrice(rawMaterialSn, DateUtil.localDateConvertToDate(LocalDate.of(year, month, i)));
                    // 价格 * 消耗重量 / 1000
                    price = price == null ? BigDecimal.ZERO : price;
                    BigDecimal cost = price.multiply(new BigDecimal(materialCostWeight)).divide(new BigDecimal("1000"));
                    // 累加原材消耗成本
                    materialCost = materialCost.add(StringUtils.isEmpty(rawMaterialSn) ? BigDecimal.ZERO : cost);
                    // 变吨四舍五入两位小数
                    BigDecimal decimal = new BigDecimal(materialCostWeight).divide(new BigDecimal(1000)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    innerMap.put(materialName, decimal);
                }

                // 原材成本
                innerMap.put("总成本(元)", materialCost.setScale(2, BigDecimal.ROUND_HALF_UP).toString());
                innerMap.put("成本(元/方)", actualOutput.equals("0") ? BigDecimal.ZERO : materialCost.divide(new BigDecimal(actualOutput), BigDecimal.ROUND_CEILING).setScale(2, BigDecimal.ROUND_HALF_UP));

                dayData.add(innerMap);
            }

            costDataDetails.add(dayData);
        }

        // 表头
        resultMap.put("titles", titles);
        // 表单数据
        resultMap.put("content", costDataDetails);
        return resultMap;
    }

    @Autowired
    public void setShipOrderService(IProductShipOrderService shipOrderService) {
        this.shipOrderService = shipOrderService;
    }
    @Autowired
    public void setDataDictService(IDataDictService dataDictService) {
        this.dataDictService = dataDictService;
    }
    @Autowired
    public void setProductionRecordService(IProductionRecordService productionRecordService) {
        this.productionRecordService = productionRecordService;
    }
    @Autowired
    public void setRecordDao(IProductionRecordDao recordDao) {
        this.recordDao = recordDao;
    }
    @Autowired
    public void setRecordDetailsDao(IProductionRecordDetailsDao recordDetailsDao) {
        this.recordDetailsDao = recordDetailsDao;
    }
    @Autowired
    public void setRawInfoService(IRawMaterialInfoService rawInfoService) {
        this.rawInfoService = rawInfoService;
    }
    @Autowired
    public void setShipOrderDao(IProductShipOrderDao shipOrderDao) {
        this.shipOrderDao = shipOrderDao;
    }
    @Autowired
    public void setRecordService(IProductionRecordService recordService) {
        this.recordService = recordService;
    }
    @Autowired
    public void setProductOverageService(IProductOverageService productOverageService) {
        this.productOverageService = productOverageService;
    }
    @Autowired
    public void setRawMaterialPriceDao(IRawMaterialPriceDao rawMaterialPriceDao) {
        this.rawMaterialPriceDao = rawMaterialPriceDao;
    }
    @Autowired
    public void setRawConfigDao(IProductionLineRawConfigDao rawConfigDao) {
        this.rawConfigDao = rawConfigDao;
    }
    @Autowired
    public void setRmDao(IRawMaterialInfoDao rmDao) {
        this.rmDao = rmDao;
    }

    private IProductShipOrderService shipOrderService;
    private IDataDictService dataDictService;
    private IProductionRecordService productionRecordService;
    private IProductionRecordDao recordDao;
    private IProductionRecordDetailsDao recordDetailsDao;
    private IRawMaterialInfoService rawInfoService;
    private IProductShipOrderDao shipOrderDao;
    private IProductionRecordService recordService;
    private IProductOverageService productOverageService;
    private IRawMaterialPriceDao rawMaterialPriceDao;
    private IProductionLineRawConfigDao rawConfigDao;
    private IRawMaterialInfoDao rmDao;
    @Autowired
    private ISaleContractDao saleContractDao;
}
